#include "base/base_buffer.h"
#include "base/channel.h"
#include "base/eventloop.h"
#include "base/timeevent.h"
#include "base/timeevery.h"
#include "base/threadpool.h"
#include "base/log.h"
#include "net/connectpool.h"
#include "net/socket.h"
#include "net/heartbeat.h"

#include <memory.h>
#include <tuple>
#include <sys/time.h>

#include "net/connect.h"
namespace net_tools::net
{
  net_tools::base::Threadpool *Connect::threadpool_ = nullptr;
  Connect::Connect(Eventloop *eventloop)
      : User_data_ptr(nullptr),
        buffer_(eventloop, this),
        once_time_job_set_(),
        every_time_job_map_(),
        channel_(nullptr),
        eventloop_(eventloop),
        heartbeat_(nullptr),
        Is_add_heartbeat_(false),
        Is_send_heartbeat_(false),
        read_callback_([](Connect *connect)
                       { connect->Print_ip_port("recv"); }),
        close_callback_([](Connect *connect)
                        { connect->Print_ip_port("close"); }),
        lose_heartbeat_callback_([](Connect *connect)
                                 { connect->Print_ip_port("lose heart beat"); }){};
  Connect::~Connect()
  {
    NT_LOG_ERROR << "err:Connect been ~" << NT_LOG_ENDL;
  };
  void Connect::Init_channel(net_tools::base::Channel *channel)
  {
    channel_ = channel;
    buffer_.Init_channel(channel_);
    channel_->Set_write_callback([this]
                                 { buffer_.Write_able_callback(); });
    channel_->Set_read_callback([this]
                                { buffer_.Read_able_callback(); });
    channel_->Set_close_callback([this]
                                 { buffer_.Close_callback(); });
  };
  void Connect::Set_address(struct sockaddr_in connect_addr)
  {
    char connect_addr_string[16];
    connect_addr_ = connect_addr;
    Socket::Nettostring(connect_addr_, connect_addr_string);
    connect_addr_string_ = std::string(connect_addr_string);
  };
  void Connect::Print_ip_port(const char *status)
  {
    NT_LOG_TRACE << "connect from IP: "
                 << connect_addr_string_
                 << " PORT:"
                 << ntohs(connect_addr_.sin_port)
                 << " Status: "
                 << status
                 << NT_LOG_ENDL;
  }

  unsigned int Connect::Read(void *buf, unsigned int max_size)
  {
    return buffer_.Read(buf, max_size);
  };

  Buffer_reader *Connect::Read()
  {
    return buffer_.Read();
  };

  bool Connect::Write(void *buf, unsigned int len)
  {
    Is_send_heartbeat_ = true;
    return buffer_.Write(buf, len);
  };

  uint32_t Connect::Peak()
  {
    return buffer_.Peak();
  };
  void Connect::Send()
  {
    buffer_.Send();
  };
  void Connect::Append(void *buf, uint32_t len)
  {
    buffer_.Append(buf, len);
  };

  void Connect::Close()
  {
    buffer_.Close();
  };
  void Connect::Close_right_now()
  {
    buffer_.Close_right_now();
  };
  void Connect::Add_task(func task)
  {
    threadpool_->Addtask(std::move(task));
  };
  void Connect::Set_read_callback(connect_func cb)
  {
    read_callback_ = std::move(cb);
  };
  void Connect::Set_close_callback(connect_func cb)
  {
    close_callback_ = std::move(cb);
  };
  void Connect::Set_lose_heartbeat_callback(connect_func cb)
  {
    lose_heartbeat_callback_ = std::move(cb);
  };

  void Connect::Read_callback()
  {
    read_callback_(this);
  };
  void Connect::Close_callback()
  {
    close_callback_(this);
    Clean_connect(); //到这整个connect被清理
  };
  void Connect::Lose_heartbeat_callback()
  {
    Heartbeat_lose_todo();
    lose_heartbeat_callback_(this);
    buffer_.Clean_buffer();
    Clean_connect();
  };
  void Connect::User_want_close_callback()
  {
    NT_LOG_INFO << "clear" << NT_LOG_ENDL;
    Clean_connect(); //到这整个connect被清理
  };
  void Connect::Heartbeat_Close_connect_todo()
  {
    heartbeat_->Del_heartbeat(this);
  };
  void Connect::Heartbeat_lose_todo()
  {
    heartbeat_->Lose_heartbeat(this);
  };
  void Connect::Rec_heartbeat()
  {
    if (heartbeat_) [[likely]]
    {
      min_heartbeat_struct_->IS_ALIVE |= heartbeat_->index_vector_[min_heartbeat_index_];
    }
  };
  void Connect::Send_heartbeat()
  {
    if (!Is_send_heartbeat_)
    {
      NT_LOG_INFO << "send heart beat" << NT_LOG_ENDL;
      Write(nullptr, 0);
    }
    Is_send_heartbeat_ = false;
  };
  void Connect::Clean_connect()
  {
    NT_LOG_INFO << "Clear" << NT_LOG_ENDL;
    eventloop_->Delevent(channel_);
    eventloop_->Free_channel_right_now(channel_);
    // clean every_time_job
    every_time_job_map_.Del_all_timejob();
    // clean once_time_job;
    once_time_job_set_.Del_all_timejob();
    eventloop_->connectpool_->Free_Connect(this);
  };
  net_tools::base::Timeevent *Connect::Add_once_time_job_after(func func_, timeval begin_time)
  {
    return eventloop_->Run_after(std::move(func_), begin_time, &once_time_job_set_);
  };
  net_tools::base::Timeevent *Connect::Add_once_time_job_at(func func_, timeval begin_time)
  {
    return eventloop_->Run_at(std::move(func_), begin_time, &once_time_job_set_);
  };
  bool Connect::Del_once_time_job(net_tools::base::Timeevent *timeevent)
  {
    return once_time_job_set_.Del_timejob(timeevent);
  };
  bool Connect::Add_every_time_job(func func_, timeval begin_time, timeval time, int count, const std::string job_name)
  {
    return eventloop_->Run_every(std::move(func_), begin_time, time, count, std::move(job_name), &every_time_job_map_)->Is_takeplace();
  };
  bool Connect::Del_every_time_job(const std::string job_name)
  {
    return every_time_job_map_.Del_timejob(job_name);
  };
  void Connect::Add_timejob_after_sec(const std::string job_name, func todo, long int begin_time, long int time, int count)
  {
    timeval now_, sec_;
    gettimeofday(&now_, NULL);
    now_.tv_sec += begin_time;
    sec_.tv_sec = time;
    sec_.tv_usec = 0;
    eventloop_->Run_every(std::move(todo), now_, sec_, count, std::move(job_name), &every_time_job_map_);
  };
  std::string *Connect::Get_Thread_name()
  {
    return eventloop_->Get_Thread_name();
  };

} // namespace net_tools::net